package ru.nsu.fit.ws.get_questions;

import ru.nsu.fit.shared.data_base_manager.DatabaseManager;
import ru.nsu.fit.shared.error_codes.ErrorCodes;
import ru.nsu.fit.shared.questions_request.QuestionsGetterInputForDB;
import ru.nsu.fit.shared.questions_request.QuestionsGetterOutputFromDB;

import javax.jws.HandlerChain;
import javax.jws.WebService;
import java.sql.SQLException;
import static ru.nsu.fit.shared.error_codes.ErrorCodes.*;

/**
 * Created by IntelliJ IDEA.
 * User: vtimofeev
 * Date: 12/12/12
 * Time: 10:36 PM
 * To change this template use File | Settings | File Templates.
 */
@WebService(endpointInterface = "ru.nsu.fit.ws.get_questions.QuestionsGetter")
@HandlerChain(file= "handler-chain.xml")
public class QuestionsGetterImpl implements QuestionsGetter{

    private static final int MAX_QUESTIONS_PER_REQUEST = 50;
    private static final int PI_IN_DEGREES = 180;
    //Diameter of Earth
    private static final int MAX_QUESTION_RADIUS = 12756;

    @Override
    public QuestionsGetterOutput getQuestions(QuestionsGetterInput input) {

        long userSessionId = input.getUserSessionId();
        int questionNumber = input.getQuestionNumber();
        int questionsOffset = input.getQuestionsOffset();

        double latitude = input.getLatitude();
        double longitude = input.getLongitude();
        double radius = input.getRadius();

        try {
            int userID = DatabaseManager.getUserId(userSessionId);
            if (userID < 0) {
                return createQuestionsGetterOutput(NOT_AUTHORIZED);
            }

            if (!validateQuestionsGetterInput(input)) {
                return createQuestionsGetterOutput(WRONG_QUESTIONS_REQUEST);
            }

            QuestionsGetterInputForDB inputForDB = new QuestionsGetterInputForDB(
                    userID, questionNumber, questionsOffset, latitude, longitude, radius);

            QuestionsGetterOutputFromDB outputFromDB = DatabaseManager.getQuestions(inputForDB);

            return createQuestionsGetterOutput(outputFromDB);

        } catch (SQLException e) {
            e.printStackTrace();
            return createQuestionsGetterOutput(DATABASE_ERROR);
        }
    }

    // Carefully validate input to determine whether it should be sent to Database
    private boolean validateQuestionsGetterInput(QuestionsGetterInput input) {

        int questionNumber = input.getQuestionNumber();
        int questionsOffset = input.getQuestionsOffset();

        double latitude = input.getLatitude();
        double longitude = input.getLongitude();
        double radius = input.getRadius();

        // Note that if SOAP message doesn't contain location, every double will have 0.0d
        if ((questionNumber > 0) && (questionNumber <= MAX_QUESTIONS_PER_REQUEST) &&
            (questionsOffset >= 0) &&
            ((latitude >= -PI_IN_DEGREES)&&(latitude <= PI_IN_DEGREES) || (latitude == 0.0d)) &&
            ((longitude >= -PI_IN_DEGREES)&&(longitude <= PI_IN_DEGREES) || (longitude == 0.0d)) &&
            ((radius > 0)&&(radius <= MAX_QUESTION_RADIUS) || (radius == 0.0d))) {
            return true;
        }

        return false;
    }

    // Used if error occurs
    private QuestionsGetterOutput createQuestionsGetterOutput
            (ErrorCodes errorCode) {

        // All fields are zero(or null) initially
        QuestionsGetterOutput output = new QuestionsGetterOutput();

        output.setErrorCode(errorCode.getCode());
        output.setErrorMessage(errorCode.getMessage());

        return output;
    }

    // Used if NO error occurs
    private QuestionsGetterOutput createQuestionsGetterOutput
    (QuestionsGetterOutputFromDB outFromDB) {

        QuestionsGetterOutput output = new QuestionsGetterOutput();

        output.setQuestionTexts(outFromDB.questionTexts);
        output.setAnswers(outFromDB.answers);
        output.setLifetimes(outFromDB.lifetimes);
        output.setQuestionIds(outFromDB.questionIds);
        output.setAnswerIds(outFromDB.answerIds);

        ErrorCodes errorCode = NO_ERROR;
        output.setErrorCode(errorCode.getCode());
        output.setErrorMessage(errorCode.getMessage());

        return output;
    }
}
